package com.github.yangyishe.p400;

import java.util.*;

/**
 * 399. 除法求值
 * https://leetcode.cn/problems/evaluate-division/description/?envType=study-plan-v2&envId=top-interview-150
 *
 * 给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件，其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。
 *
 * 另有一些以数组 queries 表示的问题，其中 queries[j] = [Cj, Dj] 表示第 j 个问题，请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。
 *
 * 返回 所有问题的答案 。如果存在某个无法确定的答案，则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串，也需要用 -1.0 替代这个答案。
 *
 * 注意：输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况，且不存在任何矛盾的结果。
 *
 * 注意：未在等式列表中出现的变量是未定义的，因此无法确定它们的答案。
 *
 *
 *
 * 示例 1：
 *
 * 输入：equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
 * 输出：[6.00000,0.50000,-1.00000,1.00000,-1.00000]
 * 解释：
 * 条件：a / b = 2.0, b / c = 3.0
 * 问题：a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
 * 结果：[6.0, 0.5, -1.0, 1.0, -1.0 ]
 * 注意：x 是未定义的 => -1.0
 * 示例 2：
 *
 * 输入：equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
 * 输出：[3.75000,0.40000,5.00000,0.20000]
 * 示例 3：
 *
 * 输入：equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
 * 输出：[0.50000,2.00000,-1.00000,-1.00000]
 *
 *
 * 提示：
 *
 * 1 <= equations.length <= 20
 * equations[i].length == 2
 * 1 <= Ai.length, Bi.length <= 5
 * values.length == equations.length
 * 0.0 < values[i] <= 20.0
 * 1 <= queries.length <= 20
 * queries[i].length == 2
 * 1 <= Cj.length, Dj.length <= 5
 * Ai, Bi, Cj, Dj 由小写英文字母与数字组成
 */
public class Problem399 {
    public static void main(String[] args) {
        List<List<String>> equations = Arrays.asList(
                Arrays.asList("a","b"),
                Arrays.asList("b","c"),
                Arrays.asList("bc","cd")
        );
        double[] values = new double[]{1.5,2.5,5.0};
        List<List<String>> queries = Arrays.asList(
                Arrays.asList("a","c"),
                Arrays.asList("c","b"),
                Arrays.asList("bc","cd"),
                Arrays.asList("cd","bc")
        );

        Problem399 problem399 = new Problem399();
        double[] doubles = problem399.calcEquation(equations, values, queries);
        System.out.println(Arrays.toString(doubles));
    }

    /**
     * 数学思路:
     * 根据前两个参数, 构建倍数关系.
     * 第三个参数, 则由倍数关系, 求出最终值
     *
     * 倍数关系, 可考虑使用哈希表实现. 如 a:b=2,a:c=3这样.
     *
     * @param equations
     * @param values
     * @param queries
     * @return
     */
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
        for(int i=0;i<equations.size();i++){
            List<String> strings = equations.get(i);
            double val=values[i];

            String s1 = strings.get(0);
            String s2 = strings.get(1);
            chartMap.putIfAbsent(s1,new HashMap<>());
            chartMap.get(s1).put(s2,val);
            if(val!=0){
                chartMap.putIfAbsent(s2,new HashMap<>());
                chartMap.get(s2).put(s1,1/val);
            }
        }

        double[] results=new double[queries.size()];
        for(int i=0;i<queries.size();i++){
            List<String> query=queries.get(i);
            double result=calcResult(query.get(0),query.get(1),new HashSet<>());
            results[i]=result;
        }

        return results;
    }
    Map<String, Map<String,Double>> chartMap=new HashMap<>();

    private double calcResult(String start, String end, Set<String> usedSet){
        if(!chartMap.containsKey(start)){
            return -1;
        }
        if(start.equals(end)){
            return 1;
        }
        if(usedSet.contains(start)){
            return -1;
        }
        usedSet.add(start);
        Map<String, Double> eachChartMap = chartMap.get(start);
        for(String mid:eachChartMap.keySet()){
            double result=calcResult(mid,end,usedSet);
            if(result>=0){
                return result*eachChartMap.get(mid);
            }
        }

        return -1;

    }


}
